/*********************************************************************
* File: Agent.h
*
* \brief Implements the agent. 
*********************************************************************/
#pragma once

#include <float.h>

#include "../engine.h"
#include "../game/globals.h"
#include "../game/World.h"
using namespace game;
#include "IAgent.h"
#include "globals.h"
using namespace agents;
#include "modules/WaypointNavigation.h"
#include "modules/Communication.h"
#include "modules/Finances.h"
#include "modules/Combat.h"
#include "modules/Senses.h"
using namespace agents::modules;

#include <list>
using namespace std;


namespace agents{
	/**
	* \brief Implements the agent.
	* 
	* \author Instituto Superior Tecnico de Lisboa, Portugal
	* \author Technical University of Lisbon, Portugal
	* 
	* \author Agentes Autonomos e Sistemas Multiagente
	* \author Autonomous Agents and Multiagent Systems
	* 
	* \version	1.0
	* \date		2006/2007
	**/
	class Agent: public IAgent {
	public:
		//*********************************************************************
		// Static methods/members
		//*********************************************************************
		/** 
		* \brief Counts the number of agents. 
		*
		* Used to create agent ids. 
		**/
		static int counter;
		/** 
		* \brief Gets the agent associated with an entity. 
		*
		* \param[in] pent The entity.
		**/
		static Agent *getInstance( edict_t *pent );
		/** 
		* \brief Gets the agent class from its entity variables. 
		*
		* \param[in] pev The entity variables.
		**/
		static Agent *getInstance( entvars_t *pev ) { return getInstance( ENT( pev ) ); }
		/** 
		* \brief Gets the agent class from an entity offset. 
		*
		* \param[in] pev The entity offset.
		**/
		static Agent *getInstance( int eoffset ) { return getInstance( ENT( eoffset) ); }

		//*********************************************************************
		// Methods
		//*********************************************************************
		Agent(edict_t *entity, int team, int model);
		~Agent();

		/** 
		* \brief Gets the agent's unique id. 
		**/
		int getUniqueId(){ return _id; }
		/** 
		* \brief Gets the agent's name. 
		**/
		char* getName(){ return _name; }
		CounterStrikeTeams::Enumeration getTeam();
		int getHealth();
		bool hasTakenDamage();

		/**
		* \brief Gets the world interface.
		*
		* \see agents::interfaces::IAgent::getWorld
		**/
		IWorld& getWorld(){ return *g_world; }
		/**
		* \brief Gets the collision handler interface.
		*
		* \see agents::interfaces::IAgent::getCollisionHandler
		**/
		ICollisionHandler& getCollisionHandler(){ return *navigation; }
		/**
		* \brief Gets the collision manager interface.
		*
		* \see agents::interfaces::IAgent::getCollisionManager
		**/
		ICollisionManager& getCollisionManager(){ return *navigation; }
		/**
		* \brief Gets the navigation interface.
		*
		* \see agents::interfaces::IAgent::getNavigation
		**/
		INavigation& getNavigation(){ return *navigation; }
		/**
		* \brief Gets the free navigation interface.
		*
		* \see agents::interfaces::IAgent::getFreeNavigation
		**/
		IFreeNavigation& getFreeNavigation(){ return *navigation; }
		/**
		* \brief Gets the reactive waypoint navigation interface.
		*
		* \see agents::interfaces::IAgent::getReactiveWaypointNavigation
		**/
		IReactiveWaypointNavigation& getReactiveWaypointNavigation(){ return *navigation; }
		/**
		* \brief Gets the waypoint navigation interface.
		*
		* \see agents::interfaces::IAgent::getWaypointNavigation
		**/
		IWaypointNavigation& getWaypointNavigation(){ return *navigation; }
		/**
		* \brief Gets the combat interface.
		*
		* \see agents::interfaces::IAgent::getCombat
		**/
		ICombat& getCombat(){ return *combat; }
		/**
		* \brief Gets the finances interface.
		*
		* \see agents::interfaces::IAgent::getFinances
		**/
		IFinances& getFinances(){ return *finances; }
		/**
		* \brief Gets the communication interface.
		*
		* \see agents::interfaces::IAgent::getCommunication
		**/
		ICommunication& getCommunication(){ return *communication; }
		/**
		* \brief Gets the vision interface.
		*
		* \see agents::interfaces::IAgent::getVision
		**/
		IVision& getVision(){ return *senses; }
		/**
		* \brief Gets the hearing interface.
		*
		* \see agents::interfaces::IAgent::getHearing
		**/
		IHearing& getHearing(){ return *senses; }
		/**
		* \brief Gets the radar interface.
		*
		* \see agents::interfaces::IAgent::getRadar
		**/
		IRadar& getRadar(){ return *senses; }

		virtual void newRound();
		void main();

		/** 
		* \brief Gets this agent's engine entity.
		**/
		edict_t *getEdict(){ return ENT( pev ); };

		/** 
		* \brief Gets the agent's center position.
		**/
		Vector centerPosition() { return (pev->absmax + pev->absmin) * 0.5; };
		/** 
		* \brief Gets the agent's eyes position.
		**/
		Vector eyePosition() { return pev->origin + pev->view_ofs; };
		/** 
		* \brief Gets the agent's ears position.
		**/
		Vector earPosition() { return pev->origin + pev->view_ofs; };

		bool isOnLadder(void);
		bool isInWater(void);
		bool isDeadlyDrop(Vector target);
		bool isWallOnLeft(int distanceToTheLeft = 40);
		bool isWallOnRight(int distanceToTheRight = 40);
		bool canDuckUnder(Vector vNormal);
		bool canJumpUp(Vector vNormal);
		bool canStrafeLeft(TraceResult *tr);
		bool canStrafeRight(TraceResult *tr);
		bool canMoveForward(Vector vNormal,TraceResult *tr );

		//*********************************************************************
		// Variables
		//*********************************************************************
		/** 
		* \brief Navigation API.
		**/
		WaypointNavigation *navigation;
		/** 
		* \brief Communication API.
		 **/
		Communication *communication;
		/** 
		* \brief Buying API.
		**/
		Finances *finances;
		/** 
		* \brief Combat API. 
		**/
		Combat *combat;
		/** 
		* \brief Senses API.
		**/
		Senses* senses;

		/** 
		* \brief The engine entity's variables.
		**/
		entvars_t *pev;

		/** 
		* \brief Time this agent was spawned.
		**/
		float spawnTime;
		/** 
		* \brief The team the agent whishes to join.
		**/
		int wantedTeam;
		/** 
		* \brief The class (model) the agent whishes to have.
		**/
		int  wantedClass;
		/** 
		* \brief Team/class selection state.
		**/
		GameStartActions::Enumeration startAction;
		/** 
		* \brief Whether the team and class has been chosen yet.
		**/
		bool started;
		/** 
		* \brief In assassination maps, whether the agent is the VIP.
		**/
		bool isVIP;
		/** 
		* \brief Stores the last damage type.
		**/
		int lastDamageType;

	protected:
		void startGame();
		void preThink();
		virtual void think();
		void postThink();

		/** 
		* \brief Whether to do the 'think' step. 
		*
		* Should be set to 'false' every cycle the 'think' step is to be skipped.
		**/
		bool _doThink;
		/** 
		* \brief Whether to do the 'postThink' step. 
		*
		* Should be set to 'false' every cycle the 'postThink' step is to be skipped.
		**/
		bool _doPostThink;

	private: 
		/** 
		* \brief Whether the starting aim target was set.
		**/
		bool _startAimTargetSet;
		/** 
		* \brief The agent's unique id.
		**/
		int	_id;
		/** 
		* \brief The agent's name.
		**/
		char _name[AGENT_NAME_MAX_LENGTH];
		/** 
		* \brief Whether the agent is alive.
		**/
		bool _isAlive;
	};
}